Use case: conversion in DMA mode

Description of usage

Operation

HAL1

HAL2

Start conversion in DMA Mode

Activate the ADC peripheral and start conversions in DMA mode using HAL_ADC_Start_DMA(). Specify the buffer where the ADC data will be stored and the length of the buffer.

Activate the ADC peripheral and start conversions using HAL_ADC_Start().

Note

From this point, the ADC internal analog hardware is enabled, inducing a slight current consumption.

Start conversion with a trigger using HAL_ADC_REG_StartConv_DMA().

Note

The conversion trigger can be:

  • A software start: calls the function for each conversion.

  • From another peripheral (timer, for instance): calls the function once.

Calibration (optional)

  • Start calibration using HAL_ADCEx_Calibration_Start().

  • Get calibration value using HAL_ADCEx_Calibration_GetValue().

  • Set calibration value using HAL_ADCEx_Calibration_SetValue().

  • Calibrate the ADC using HAL_ADC_Calibrate().

  • Get calibration factor using HAL_ADC_GetCalibrationFactor().

  • Set calibration factor using HAL_ADC_SetCalibrationFactor().

DMA transfer complete callback

Implement the HAL_ADC_ConvCpltCallback() callback, which is called when the DMA transfer is complete. This callback function handles the completed conversion.

Implement the HAL_ADC_REG_DataTransferCpltCallback() callback, which is called when the DMA transfer is complete. This callback function handles the completed conversion.

DMA half-transfer callback

Implement the HAL_ADC_ConvHalfCpltCallback() callback, which is called when the DMA half-transfer is complete. This callback function handles the half-completed conversion.

Implement the HAL_ADC_REG_DataTransferHalfCallback() callback, which is called when the DMA half-transfer is complete. This callback function handles the half-completed conversion.

Retrieve conversion results

The conversion results are stored in the buffer specified in HAL_ADC_Start_DMA(). Process the data in the transfer complete and half-transfer complete DMA callbacks.

The conversion results are stored in the buffer specified in HAL_ADC_REG_StartConv_DMA(). Process the data in the transfer complete and half-transfer complete DMA callbacks.

Stop conversion

  • Stop potential ongoing conversions on the regular and injected ADC groups and disable the ADC peripheral using HAL_ADC_Stop_DMA().

  • Stop potential ongoing conversions on the regular ADC group and disable the ADC peripheral using HAL_ADCEx_RegularStop_DMA().

  • If the conversion trigger is not a software start (from another peripheral, such as a timer), stop the conversion using HAL_ADC_REG_StopConv_DMA().

  • Stop the ADC using HAL_ADC_Stop().

Loop for multiple iterations

N/A

Multiple iterations for starting and stopping conversions are possible.

Warning

If multiple conversions are required, do not fully stop the ADC using the HAL_ADC_Stop() function.

Sequence diagram

ADC data transfer in DMA mode

@startuml

participant "User application\n(thread mode)" as appli
participant "User application\n(handler mode)" as appli_IRQ
participant "<font color=green><b>HAL ADC</b></font>" as ADC
participant "<font color=green><b>HAL DMA</b></font>" as DMA
participant "System HW interruption" as interruption

group#Bisque #Linen ADC operation
appli->ADC : HAL_ADC_Start_DMA()
note right
From this point, the ADC internal analog hardware is
enabled (inducing a slight current consumption) and
conversion in DMA mode starts.
end note
return
appli->ADC : HAL_ADCEx_Calibration_Start()
return

ADC->ADC : Enable ADC selected interruptions\nEnable DMA request\nEnable ADC conversion trigger
interruption <[#purple]-x? : <font color=purple><b>DMA IRQ event\n(transfer complete)
interruption -> appli_IRQ : DMAx_IRQHandler()
activate appli_IRQ #DarkSalmon
appli_IRQ -> DMA : HAL_DMA_IRQHandler()
DMA -> DMA : Clear flag
DMA->ADC : Callback function pointer
ADC -> appli_IRQ: HAL_ADC_ConvCpltCallback()
appli_IRQ -> appli_IRQ : User application processing
appli_IRQ -> interruption : (Return from ISR)
deactivate appli_IRQ

appli->ADC : HAL_ADC_Stop_DMA()
return
end

@enduml

Code snippet

HAL1

HAL2

#define ADC_BUFFER_SIZE 10
uint32_t adcBuffer[ADC_BUFFER_SIZE];

int main(void)
{
    // Add your Init and config code

    if (HAL_ADC_Start_DMA(&hadc1, (uint32_t*)adcBuffer, ADC_BUFFER_SIZE) != HAL_OK)
    {
        /* Start Error */
        Error_Handler();
    }

}

/* Error Handler */
void Error_Handler(void)
{
    while (1)
    {
       /* Stay in this loop in case of error */
    }
}

/* ADC conversion complete callback */
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{
    /* Stop ADC conversion and DMA transfer */
    HAL_ADC_Stop_DMA(hadc);
    /* Handle the completed conversion data */
    for (int i = 0; i < ADC_BUFFER_SIZE; i++)
    {
      /* Process adcBuffer[i] */
    }
}
#define ADC_BUFFER_SIZE 10
uint32_t adcBuffer[ADC_BUFFER_SIZE];
/* Loop for Multiple Iterations  var */
uint32_t TestLoop = 3;

int main(void)
{
    // Add your Init and config code

    /* ADC activation */
    HAL_ADC_Start(&hadc1);

    while (TestLoop != 0)
    {
       /* ADC with DMA measurement */
      if (HAL_ADC_REG_StartConv_DMA(&hadc1, (uint32_t*)adcBuffer, ADC_BUFFER_SIZE) != HAL_OK)
      {
          /* Start Error */
          Error_Handler();
      }
      /* Wait time for ADC conversion */
      HAL_Delay(5);
      TestLoop--;
    }
    /* Stop ADC */
    HAL_ADC_Stop();
}

/* Error Handler */
void Error_Handler(void)
{
    while (1)
    {
       /* Stay in this loop in case of error */
    }
}

/* ADC conversion complete callback */
void HAL_ADC_REG_DataTransferCpltCallback(hal_adc_handle_t *hadc)
{
    /* Stop ADC conversion and DMA transfer */
    HAL_ADC_REG_StopConv_DMA(hadc);
    /* Handle the completed conversion data */
    for (int i = 0; i < ADC_BUFFER_SIZE; i++)
    {
      /* Process adcBuffer[i] */
    }
}

Key changes

  1. The split of the activate and start conversion in DMA mode functions.

  2. The split of the disable and stop conversion in DMA mode functions.